<?php
namespace Framework\Cache;

class FileStore extends Store
{

	/**
	 * @var 缓存目录
	 * 后期应该预先设定
	 */
	public $path;

    /**
     * @var 字符串缓存文件后缀。 默认为 '.bin'
     */
	public $suffix = '.bin';

	/**
	 * @var int 存储缓存文件的子目录的级别。 默认为 1。
	 * 如果系统有大量缓存文件（例如一百万），您可以使用更大的值
	 *（通常不大于 3）。 使用子目录主要是为了保证文件系统
	 * 不会因为单个目录包含太多文件而负担过重。
 	*/
	public $directoryLevel = 1;

	public function init()
	{
		//path目录不存在则创建
        if (!is_dir($this->path)) {
            throw new \Exception("Error Processing Request", 1);
        }
	}

    protected function getCacheFile($normalizedKey)
	{
        $cacheKey = $normalizedKey;

        if ($this->prefix !== '') {
            // 删除键前缀以避免生成恒定的目录级别
            $lenKeyPrefix = strlen($this->prefix);
            $cacheKey = substr_replace($normalizedKey, '', 0, $lenKeyPrefix);
        }

        $cachePath = $this->path;

        if ($this->directoryLevel > 0) {
            for ($i = 0; $i < $this->directoryLevel; ++$i) {
                if (($subDirectory = substr($cacheKey, $i + $i, 2)) !== false) {
                    $cachePath .= DIRECTORY_SEPARATOR . $subDirectory;
                }
            }
        }

        return $cachePath . DIRECTORY_SEPARATOR . $normalizedKey . $this->suffix;
	}

	protected function getValue($key)
	{
        $cacheFile = $this->getCacheFile($key);

        if (@filemtime($cacheFile) > time()) {
            $fp = @fopen($cacheFile, 'r');
            if ($fp !== false) {
                @flock($fp, LOCK_SH);
                $cacheValue = @stream_get_contents($fp);
                @flock($fp, LOCK_UN);
                @fclose($fp);
                return $cacheValue;
            }
        }

        return false;
	}

	protected function setValue($key, $value, $duration)
	{
		$cacheFile = $this->getCacheFile($key);

		//如果目录不存在 创建目录
        if ($this->directoryLevel > 0) {
        	$path = dirname($cacheFile);
	        if (!is_dir($path)) {
	        	mkdir($path, 0755);
	        }
        }

        //如果文件存在但是不属于当前用户组删除
        if (is_file($cacheFile) && function_exists('posix_geteuid') && fileowner($cacheFile) !== posix_geteuid()) {
            @unlink($cacheFile);
        }

        if (@file_put_contents($cacheFile, $value, LOCK_EX) !== false) {
            if ($duration <= 0) {
                $duration = 31536000;//365天
            }
            return @touch($cacheFile, $duration + time());
        }

        //如果有错误记录日志
        $error = error_get_last();
        app()->log->warning("Unable to write cache file '{$cacheFile}': {$error['message']}", __METHOD__);

        return false;
	}

    protected function addValue($key, $value, $duration)
    {
        $cacheFile = $this->getCacheFile($key);
        if (@filemtime($cacheFile) > time()) {
            return false;
        }

        return $this->setValue($key, $value, $duration);
    }


    protected function deleteValue($key)
    {
        $cacheFile = $this->getCacheFile($key);

        return @unlink($cacheFile);
    }

    /**
     * 从缓存中删除所有值
     */
    protected function flushValues()
    {
        $this->gc(true, false);

        return true;
    }
}